#include "CdiEngine.h"
#include "CdiBox.h"

CdiEngine::CdiEngine( WNDPROC wndProc ) 
: CdiD3DWindow( wndProc, false, 800, 600 ),
  m_lightingObjects( NULL ),
  m_gameObjects( NULL )
{
  Setup();
}

CdiEngine::CdiEngine( WNDPROC wndProc, bool FullScreen, int width, int height )
: CdiD3DWindow( wndProc, FullScreen, width, height ),
  m_lightingObjects( NULL ),
  m_gameObjects( NULL )
{
  Setup();
}

CdiEngine::~CdiEngine()
{
  if( m_gameObjects ) 
  {
    delete m_gameObjects;
  }
  if( m_camera )
  {
    delete m_camera;
  }
  if( m_lightingObjects )
  {
    delete m_lightingObjects;
  }
  
  m_lightingObjects = NULL;
  m_gameObjects = NULL;
  m_camera = NULL;
}

void CdiEngine::GameLoop()
{
  DoWork();
  if( TRUE == GetRenderingState() ) 
  {
    CalculateFrameRate();
    Render();
  }
}

void CdiEngine::Setup()
{
  m_enableRendering = TRUE;

  m_gameObjects = new CdiRenderObjectList();
  m_lightingObjects = new CdiRenderObjectList();
  m_camera = NULL;

  // Setting up Camera
  SetupCamera(  D3DXVECTOR3(127.0f, 5.0f, 40.0f), 
                D3DXVECTOR3(0,0,0), 
                D3DXVECTOR3(0,1,0) 
              );

  m_color = D3DCOLOR_XRGB( 10, 100, 10 );
}

CdiCamera* CdiEngine::GetCamera()
{
  return (CdiCamera*)m_camera;
}

void CdiEngine::DoWork()
{
  
}

void CdiEngine::Render() 
{
  // Set the camera
  SetViewMatrix(  m_camera->GetPosition(), 
                  m_camera->GetLookAt(), 
                  m_camera->GetCameraUp() );  
  
  // Update the mouse  
  UpdateMouse();

  m_pDevice->Clear( 0, 
                    NULL, 
                    D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 
                    m_color, 
                    1.0f, 
                    0 );

  m_pDevice->BeginScene();
  
  if( m_lightingObjects != NULL ) 
  {
    m_lightingObjects->RenderAll( m_pDevice );
  }

  if( m_gameObjects != NULL )
  {
    m_gameObjects->RenderAll( m_pDevice );
  }

  m_pDevice->EndScene();
  m_pDevice->Present( NULL, NULL, NULL, NULL );
}

void CdiEngine::AddObject( CdiRenderBase* renderObject )
{
  if( renderObject != NULL && 
      m_gameObjects != NULL)
  {
    m_gameObjects->AddObject( renderObject );
  }
}

// Handle the input to the camera
void CdiEngine::HandleInput( UINT Msg, WPARAM wParam, LPARAM lParam )
{
  if( m_camera != NULL )
  {
    m_camera->HandleInput(Msg, wParam, lParam );
  }
  switch( Msg ) 
  {
    
  case WM_SETFOCUS:
    {
      ResetScreen();
    } break;

  case WM_KILLFOCUS:
    {
      //SetRenderingState( FALSE );
    } break;

  case WM_KEYDOWN:
    {
      switch( wParam )
      {
      case VK_SPACE:
        {
          if( m_camera )
            m_camera->SetCameraReady( !m_camera->IsReady() );
        }
      }
    } break;

    case WM_CHAR:
    {     
    } break;
  }
}

void CdiEngine::SetupCamera(D3DXVECTOR3& Position, D3DXVECTOR3& LookAt, D3DXVECTOR3& Up)
{
  m_camera = new CdiMovementCamera( m_pDevice, Position, LookAt, Up );

  CreateViewPort();

  CreateProjectionMatrice();

  SetViewMatrix(  m_camera->GetPosition(), 
    m_camera->GetLookAt(), 
    m_camera->GetCameraUp() 
    );

  CenterMousePosition(); 
}


// Updates the camera by centering the mouse in the middle and passes the middle information to the Camera
void CdiEngine::UpdateMouse(void)
{
  if( m_camera->IsReady() )
  {
    WINDOWINFO wi;
    BOOL bWinInfo = GetWindowInfo( m_hWnd, &wi );
    
    if( bWinInfo )
    {
      m_camera->SetWindowMiddle(  m_screenWidthMiddle - wi.rcClient.left, 
                                  m_screenHeightMiddle - wi.rcClient.top );
    }
    CenterMousePosition();
  }
}

// Add lighing Objects
void CdiEngine::AddLight(CdiRenderBase* Light)
{
  if( m_lightingObjects && Light )
  {
    m_lightingObjects->AddObject( Light );
  }
}

// Get a light
D3DLIGHT9* CdiEngine::GetLight(int lightIndex)
{
  D3DLIGHT9* ret;
  ZeroMemory( &ret, sizeof( D3DLIGHT9 ) );
  if( m_lightingObjects != NULL && 
      m_lightingObjects->GetItemCount() < lightIndex ) 
  {
    CdiLightingBase* light = (CdiLightingBase*)m_lightingObjects->GetItem( lightIndex );
    *ret = light->GetLight();
  }
  return ret;
}
